package org.franca.importer.ea.processor;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.franca.core.franca.FArgument;
import org.franca.core.franca.FArrayType;
import org.franca.core.franca.FAttribute;
import org.franca.core.franca.FBroadcast;
import org.franca.core.franca.FEnumerationType;
import org.franca.core.franca.FEnumerator;
import org.franca.core.franca.FField;
import org.franca.core.franca.FInterface;
import org.franca.core.franca.FMapType;
import org.franca.core.franca.FMethod;
import org.franca.core.franca.FModel;
import org.franca.core.franca.FStructType;
import org.franca.core.franca.FTypeDef;
import org.franca.core.franca.FTypeRef;
import org.franca.core.franca.FUnionType;
import org.sparx.Attribute;
import org.sparx.Collection;
import org.sparx.Element;
import org.sparx.Method;
import org.sparx.Package;
import org.sparx.Parameter;

public class FindByName extends ImportProcessorDecorator {

	private static Logger jlog =  Logger.getLogger(FindByName.class.getName());
	
	@Override
	public Package makePackage(Package parent, FModel src,
			String packageName) {
		
		jlog.log(Level.FINE, "Retrieve Package "+src.getName());		

		return findRootPackage(parent, packageName);
		
	}
	
	
	public FindByName(ImportProcessor provider) {
		super(provider);
	}
	
	@Override
	public Element makeInterface(Package parent, FInterface src) {

		jlog.log(Level.FINE, "Retrieve Interface "+src.getName());		

		return findElementByName(parent, src.getName());
				
	}

	@Override
	public Method makeSimpleMethod(Element parent, FMethod src) {
				
		jlog.log(Level.FINE, "Retrieve Method "+src.getName());		

		return findMethodByName(parent, src.getName());
		
	}

	@Override
	public Method makeBroadcastMethod(Element parent, FBroadcast src) {
		
		jlog.log(Level.FINE, "Retrieve Broadcast "+src.getName());		

		return findMethodByName(parent, src.getName());
		
	}

	@Override
	public Parameter makeParameter(Method parent, String direction,
			FArgument src) {

		jlog.log(Level.FINE, "Retrieve Parameter "+src.getName());		

		return findParameterByName(parent, src.getName(), direction);
			}

	@Override
	public Element makeStructure(Package parent, FStructType src) {

		jlog.log(Level.FINE, "Retrieve Structure "+src.getName());		

		return findElementByName(parent, src.getName());
		
	}

	@Override
	public Element makeUnion(Package parent, FUnionType src) {

		jlog.log(Level.FINE, "Retrieve Union "+src.getName());		

		return findElementByName(parent, src.getName());
		
	}
	
	
	@Override
	public Element makeEnumeration(Package parent, FEnumerationType src) {

		jlog.log(Level.FINE, "Retrieve Enumeration "+src.getName());		

		return findElementByName(parent, src.getName());
		
	}

	private Parameter findParameterByName(Method parent, String name, String direction) {
						
		Parameter result = null;
		
		if(parent != null) {
			for(Parameter p: parent.GetParameters()) {
				if(p.GetName().equals(name) && p.GetKind().endsWith(direction)) {
					result = p;
					break;
				}
			}
		}
		
		return result;
		
	}
	
	private Element findElementByName(Package parent, String name) {
				
		try {
			return parent.GetElements().GetByName(name);			
		}
		
		catch (Exception e) {
			return null;
		}
		
			
	}	
	
	private Method findMethodByName(Element parent, String name) {

		// UNFORTUNATELY FEATURE IS NOT SUPPORTED BY EA SDK
		// Action is not supported at org.sparx.Collection.comGetByName(Native Method)
		// return parent.GetMethods().GetByName(name);
		Method result = null;
		
		if(parent != null) {
			for(Method m: parent.GetMethods()) {
				if(m.GetName().equals(name)) {
					result = m;
					break;
				}
			}
		}
		
		return result;
		
	}

	private Attribute findAttributeByName(Element parent, String name) {

		// UNFORTUNATELY FEATURE IS NOT SUPPORTED BY EA SDK
		// Action is not supported at org.sparx.Collection.comGetByName(Native Method)
		// return parent.GetAttributes().GetByName(name);

		Attribute result = null;
		
		for(Attribute a: parent.GetAttributes()) {
			if(a.GetName().equals(name)) {
				result = a;
				break;
			}
		}
				
		return result;
				
	}
	
	private Package findRootPackage(Package parent, String name) {
		
		try {
			return parent.GetPackages().GetByName(name);			
		}
		
		catch (Exception e) {
			jlog.log(Level.SEVERE, parent.GetName()+" "+name+ " "+e.toString());		
			return null;
		}
				
	}
	
	
	@Override
	public Attribute makeField(Element parent, FField src) {
		
		jlog.log(Level.FINE, "Retrieve Field "+src.getName());		

		return findAttributeByName(parent, src.getName());
		
	}


	@Override
	public Attribute makeEnumerator(Element parent, FEnumerator src) {

		jlog.log(Level.FINE, "Retrieve Enumerator "+src.getName());		

		return findAttributeByName(parent, src.getName());
		
	}


	@Override
	public Element makeTypedef(Package parent, FTypeDef src) {
		
		jlog.log(Level.FINE, "Retrieve Typedef "+src.getName());
		
		return findElementByName(parent, src.getName());
		
	}


	@Override
	public Element makeArray(Package parent, FArrayType src) {
		
		jlog.log(Level.FINE, "Retrieve Array "+src.getName());
		
		return findElementByName(parent, src.getName());
		
	}


	@Override
	public Element makeMap(Package parent, FMapType src) {
		
		jlog.log(Level.FINE, "Retrieve Map "+src.getName());		

		return findElementByName(parent, src.getName());
		
	}


	@Override
	public Attribute makeMapKey(Element parent, FTypeRef src) {
		
		jlog.log(Level.FINE, "Retrieve Map Key ");		

		return findAttributeByName(parent, "key");
				
	}


	@Override
	public Attribute makeMapValue(Element parent, FTypeRef src) {
		
		jlog.log(Level.FINE, "Retrieve Map Value ");		

		return findAttributeByName(parent, "value");
				
	}


	@Override
	public Attribute makeAttribute(Element parent, FAttribute src) {

		jlog.log(Level.FINE, "Retrieve Attribute "+src.getName());		

		return findAttributeByName(parent, src.getName());
				
	}

	
}
